#include "bs_app.h"

#define LOG_TAG        "[test]"
#include "log.h"

// #define TEST_UNIT_SPIFLASH
// #define TEST_UNIT_IMAGE
// #define TEST_UNIT_FS
// #define TEST_UNIT_LCD


#ifdef TEST_UNIT_SPIFLASH
uint32_t  is_successful;
uint8_t flash_rx_buf[256];
uint8_t flash_tx_buf[256];
int spi_flash_test(void)
{
    uint32_t flash_id;
    uint32_t temp0,temp1;
    // spi_flash_init();

    /* release power down */
    SPI_FLASH_CS_LOW();
    spi_flash_send_byte(0xAB);
    SPI_FLASH_CS_HIGH();
    delay_1ms(2);

    /* get flash id */
    SPI_FLASH_CS_LOW();
    spi_flash_send_byte(0x90);
    spi_flash_send_byte(0);
    spi_flash_send_byte(0);
    spi_flash_send_byte(0);
    temp0 = spi_flash_send_byte(0);
    temp1 = spi_flash_send_byte(0);
    SPI_FLASH_CS_HIGH();
    flash_id = temp0<<8 | temp1;

    for(int i=0; i<256; i++)
    {
        flash_tx_buf[i] = i;
    }
    /* flash id is correct */
    if(1){
        /* erases the specified flash sector */
        spi_flash_sector_erase(0);
        /* write tx_buffer data to the flash */ 
        spi_flash_buffer_write(flash_tx_buf, 0, 256);

        delay_1ms(10);

        /* read a block of data from the flash to rx_buffer */
        spi_flash_buffer_read(flash_rx_buf, 0, 256);
        // spi_flash_dma_buffer_read(tx_buffer, rx_buffer,FLASH_READ_ADDRESS,RX_BUFFER_SIZE);

        if(-1 == memory_compare(flash_tx_buf, flash_rx_buf, 256)){
            // printf("Err:Data Read and Write aren't Matching.\n\r");
            is_successful = 1;
        }

        /* spi flash test passed */
        if(0 == is_successful){
            // printf("\n\rSPI-GD25Q16 Test Passed!\n\r");
        }
    }else{
        /* spi flash read id fail */
        // printf("\n\rSPI Flash: Read ID Fail!\n\r");
    }
		return flash_id;
}
#endif

#ifdef TEST_UNIT_FILE
static uint32_t read_buf[1024];
static uint32_t read2_buf[1024];
static uint32_t write1_buf[1024];
static uint32_t write2_buf[1024];
bs_file_t test_file;
bs_file_t test2_file;

void bs_file_module_test()
{
    int size = 1024;
    int i, j, k;
    int addr;
    int repeat = 0;
    int status = 0;
    test_file.start_blk = 0;
    test_file.f_buf_base = (uint8_t *)&read_buf;
    f2_open(&test_file);
    j = 0;
    repeat = 1000;
    // while(repeat != 0) {
    //     // 每次写入 4k 数据
    //     for(i=0; i<size; i++)
    //     {
    //         read_buf[i] = j;
    //         j++;
    //     }
    //     GPIO_BOP(GPIOB) = GPIO_PIN_7;
    //     f2_write(&test_file, read_buf, size*4);
    //     GPIO_BC(GPIOB) = GPIO_PIN_7;
    //     repeat--;
    // }
    // f2_close(&test_file);

    static bs_sf_request_t bd_desc;
    static bs_sf_request_t bd_desc2;
    bs_sf_request_t *bd = &bd_desc;

    for(i=0; i<1024; i++)
    {
        write1_buf[i] = i;
    }
    for(i=0; i<1024; i++)
    {
        write2_buf[i] = i+0x10;
    }

    // 提交一个请求
    bd->b_blocknr = 100;
    bd->b_addr = 100*4096;
    bd->b_data = (uint8_t *)write1_buf;
    bd->b_size = 512;
    bd->b_lock = 1;
    bd->b_update = 0;
    bd->nr_sectors = 16;
    bs_sf_make_request(bd, 1);
    delay_1ms(10);
    
    // 提交第一个请求
    // bd = &bd_desc2;
    // bd->b_blocknr = 100;
    // bd->b_addr = 101*4096;
    // bd->b_data = (uint8_t *)write2_buf;
    // bd->b_size = 512;
    // bd->b_lock = 1;
    // bd->b_update = 0;
    // bd->nr_sectors = 16;
    // bs_sf_make_request(bd, 1);
    // 写入第一个区域
    while(repeat--) bs_spiflash_process();
    // 抽口读取第二块数据
    // while(bd_desc.b_lock) bs_spiflash_process();
    // while(bd_desc2.b_lock) bs_spiflash_process();

    // 回读
    // addr = 100*4096;
    // for (i=0,j=0; i<4096/4; i++) {
    //     spi_flash_buffer_read((uint8_t *)&j, addr, 4);
    //     if (i != j) {
    //         __NOP();
    //     }
    //     addr += 4;
    // }
    // // 回读
    // addr = 101*4096;
    // for (i=0,j=0; i<4096/4; i++) {
    //     spi_flash_buffer_read((uint8_t *)&j, addr, 4);
    //     if (i+0x10 != j) {
    //         __NOP();
    //     }
    //     addr += 4;
    // }
    
    // 读取第二个区域
    j = 0;
    test_file.start_blk = 101;
    test_file.f_buf_base = (uint8_t *)&read_buf;
    f2_open(&test_file);
		
    test2_file.start_blk = 101;
    test2_file.f_buf_base = (uint8_t *)&read2_buf;
    f2_open(&test2_file);
		
    // 每次读 4byte
    for (i=0; i<1024; i++) {
        status = 1;
        while(status) {
            GPIO_TG(GPIOB) = GPIO_PIN_7;
            status = f2_bread(&test_file, &j, 4);
            bs_spiflash_process();
        };
        if (i+0x10 != j) {
           goto error;
        }

        // 每次读取 4byte
        status = 1;
        while(status) {
            status = f2_bread(&test2_file, &j, 4);
            bs_spiflash_process();
        };
        if (i+0x10 != j) {
            goto error;
        }
    }

    // while(bd_desc.b_lock) bs_spiflash_process();
    // addr = 100*4096;
    // for (i=0,j=0; i<4096/4; i++) {
    //     spi_flash_buffer_read((uint8_t *)&j, addr, 4);
    //     if (i != j) {
    //        goto error;
    //     }
    //     addr += 4;
    // }


    while(1){;}
error:
    __NOP();
    while(1){;}

}
#endif

#ifdef TEST_UNIT_FS
static FIL gfile;
static FIL gfile2;
static uint8_t data_buf[4096];
static uint8_t data2_buf[4096];
extern JF_FILE journal_file;
void test_flash_write(void);
#if 0
void bs_fs_module_test()
{
    // flash全擦 从0到 
    // uint32_t addr;
    uint32_t cont = 0;
    uint32_t *pData = (uint32_t *)data_buf;
    // spi_flash_bulk_erase();
    // for(addr=0; addr<=16*1024*1024-256; addr+=256) {
    //     for(int i=0; i<64; i++) pData[i] = cont++;
    //     spi_flash_page_write(data_buf, addr, 256);
    // }
    // return;
        // spi_flash_buffer_read_block(data_buf, 2*4096, 4096);
// spi_flash_buffer_read_block(data_buf, 3*4096, 4096);;
    
    FIL *fp = &gfile;
    DWORD free_clst;
    // f_mkfs(0);

    for (int i=0; i<4096; i++) data_buf[i] = i;

    f_open(fp, "test_0", FA_OPEN_ALWAYS);

    fp = &gfile2;
    // f_open(fp, "test_1", FA_OPEN_ALWAYS|FA_READ | FA_WRITE);
    // f_write(fp, data_buf, 40, NULL);
    // f_close(fp);

    // f_open(fp, "test_1", FA_READ);
    // f_read(fp, data2_buf, 40, NULL);
    // f_close(fp);

    // f_open(fp, "test_2", FA_OPEN_ALWAYS|FA_READ | FA_WRITE);
    // f_write(fp, data_buf, 40, NULL);
    // f_close(fp);

    // f_open(fp, "main_s12.o", FA_READ);
    // f_read(fp, data2_buf, 40, NULL);
    // f_close(fp);

    f_getfree(NULL, &free_clst);
    // 连续写入，每次写入 1K
    uint32_t sect = 0;

    /***************************************** */
    cont = 0;
    // f_open(fp, "test_0", FA_OPEN_ALWAYS|FA_READ | FA_WRITE);

    // for(sect=0; sect<16*20; sect++) {
    //     // 每次写入 4k
    //     for(int i=0; i<4096/4; i++) pData[i] = cont++;
    //     f_write(fp, data_buf, 1024, NULL);
    //     f_write(fp, data_buf+1024, 1024, NULL);
    //     f_write(fp, data_buf+1024*2, 1024, NULL);
    //     f_write(fp, data_buf+1024*3, 1024, NULL);
    // }
    // f_close(fp);

    // // 读取校验
    // cont = 0;
    // f_open(fp, "test_0", FA_READ);
    // for(sect=0; sect<320; sect++) {
    //     // 每次读取 4k
    //     f_read(fp, data_buf, 4096, NULL);
    //     for(int i=0; i<4096/4; i++,cont++) {
    //         if (pData[i] != cont)
    //           goto error;
    //     }
    // }

    // f_close(fp);

    // 读取校验
    cont = 0;
    f_open(fp, "test_1", FA_READ);

    for(sect=0; sect<640; sect++) {
        // 每次读取 4k
        f_read(fp, data_buf, 4096, NULL);
        for(int i=0; i<4096/4; i++,cont++) {
            if (pData[i] != cont)
               __NOP();
						   //goto error;
        }
    }
    f_close(fp);

    // 读取校验
    cont = 0;
    f_open(fp, "test_3", FA_READ);

    // for(sect=0; sect<640; sect++) {
    //     // 每次读取 4k
    //     f_read(fp, data_buf, 4096, NULL);
    //     for(int i=0; i<4096/4; i++,cont++) {
    //         if (pData[i] != cont)
    //             __NOP();
	// 					    goto error;
    //     }
    // }
    f_close(fp);

    // 删除文件
    f_unlink("test_3");
    f_getfree(NULL, &free_clst);

    // 继续 写入
    cont = 0;
    f_open(fp, "test_1", FA_CREATE_ALWAYS|FA_READ | FA_WRITE);

    for(sect=0; sect<3*40; sect++) {
        // 每次写入 4k
        for(int i=0; i<4096/4; i++) pData[i] = cont++;
        f_write(fp, data_buf, 1024, NULL);
        f_write(fp, data_buf+1024, 1024, NULL);
        f_write(fp, data_buf+1024*2, 1024, NULL);
        f_write(fp, data_buf+1024*3, 1024, NULL);
    }
    f_close(fp);

    // 读取校验
    cont = 0;
    f_open(fp, "test_1", FA_READ);

    for(sect=0; sect<120; sect++) {
        // 每次读取 4k
        f_read(fp, data_buf, 4096, NULL);
        for(int i=0; i<4096/4; i++,cont++) {
            if (pData[i] != cont)
              goto error;
        }
    }
    f_close(fp);


    __NOP();
error:
    __NOP();

    return;
}

#else
void bs_fs_module_test()
{
    // uint32_t st_addr = 10*4096;
    // uint32_t cur_addr = st_addr;
    // spi_flash_sector_erase(st_addr);

    // 然后写入数据，每次写入 2bit
    // uint32_t pos;
    // uint8_t  cb;
    // uint8_t read;
    // uint32_t bm_pos;

    // LSB 写入
    // for (pos=0; pos<4095;pos++) {
    //     bm_pos = pos % 4 * 2;
    //     cur_addr = st_addr + pos/4;

    //     cb = (0x03<<bm_pos) ^ 0xFFFFFFFF;
    //     GPIO_BOP(GPIOB) = GPIO_PIN_0;
    //     spi_flash_page_write(&cb, cur_addr, 1);
    //     GPIO_BC(GPIOB) = GPIO_PIN_0;

    //     // 回读验证
    //     spi_flash_buffer_read(&read, cur_addr, 1);
    //     if ( (read&(0x03<<bm_pos)) != 0) {
    //         __NOP();
    //     }
    // }

    /*********** 验证日志写入 **************/
    // jf_delete();
    // bs_write_bkp_reg(1, 0);
    // return;
    uint32_t len;
    uint32_t count = bs_read_bkp_reg(1);
    JF_FILE *fp = &journal_file;
    for(int i=0; i<4096; i++) {
        len = sprintf((char *)data_buf, "This is log:%d\r\n", count);
        GPIO_BOP(GPIOB) = GPIO_PIN_0;
        jf_write(data_buf, len);
        GPIO_BC(GPIOB) = GPIO_PIN_0;
        count++;
    }
    
    bs_write_bkp_reg(1, count);
    printf("addr: 0x%X, value: %d\r\n", fp->ofs_sect,count);
    printf("write compelete!\r\n");
}
#endif
#endif

#ifdef TEST_UNIT_WEAR_FLASH

wear_level_flash_t update_region;
uint32_t start_value = 0;
uint32_t debug_cnt = 0;

static int flash_level_init(wear_level_flash_t *wl)
{
    // 初始化一些常量
    wl->page_size = UPDATE_REGION_PAGE_SIZE;
    wl->entry_size = UPDATE_REGION_ENTRY_SIZE;
    wl->st_page = INNR_UPDATE_REGION_STADDR;
    wl->page_nr = 2;
    wl->end_page = wl->st_page + (wl->page_nr-1)*wl->page_size;

    // 扇区的最后一个条目的地址
    wl->last_entry = __ROUNDDOWN(wl->page_size-1, wl->entry_size);

    flash_level_find_entry(wl);
    // 此时 wl->cur_addr 地址必须是有效的
    return 0;
}

int inner_falsh_test()
{
    // __disable_irq();
    uint32_t used_cnt;
    uint32_t index;
    uint32_t limit_addr = INNR_UPDATE_REGION_STADDR + 2*UPDATE_REGION_PAGE_SIZE;
    uint32_t limit_value = 0;
    wear_level_flash_t *wl = &update_region;
    flash_level_init(wl);
    LOGI("test inner flash eraser/write start...");
    // flash_level_reset(wl);
    // flash_level_write_entry(wl, 0, 0);
    // flash_level_find_entry(wl);
    
    start_value = wl->u.data.used_count;
    for(index = 0; index<=0x1000; index++) {
        flash_level_find_entry(wl);
        used_cnt = wl->u.data.used_count;
        if (used_cnt != index+start_value) {
            LOGE("error...");
        }
        used_cnt++;
        debug_cnt++;
        flash_level_write_entry(wl);
        limit_value = *(uint32_t *)limit_addr;
        if (limit_value != 0xFFFFFFFF)
            LOGE("out of cross!");
    }
    LOGI("test inner flash eraser/write end")

    return 0;
}
#endif

#ifdef TEST_UNIT_LCD

#endif

#ifdef TEST_UNIT_IMAGE
static char *file_list[] = {"test_image_1", "test_image_2"};
void bs_image_module_test()
{
    struct bs_image_node node;
    FIL file;
    node.limit = 0xFFFF;
    node.inv_limit = ~0xFFFF;
    node.used_count = 0;
    node.inv_used_count = ~0;
    node.ok_count = 0;
    node.inv_ok_count = ~0;
    
    // printf("file_list: %d\r\n", strlen(file_list[0])+1);
    printf("file_list: %d\r\n", node.used_count);
    GPIO_BOP(GPIOB) = GPIO_PIN_0;
    memcpy(node.file_name, file_list[0], strlen(file_list[0])+1);
    GPIO_BC(GPIOB) = GPIO_PIN_0;
    bs_imgr_add_image(&node, &file);
}

#endif

int ice_download_start(void);
extern wear_level_flash_t      img_burn_info;

char * strncpy(char * dest,const char *src,size_t count)
{
	char *tmp = dest;

	while (count-- && (*dest++ = *src++) != '\0')
		/* nothing */;

	return tmp;
}


int bs_units_test(uint8_t key)
{
#if 0
    // uint32_t addr = INNR_IMAGE_REGION_STADDR + 4*1024;
    // uint32_t data[32];
    // uint32_t tmp_u32;
    static uint8_t choice = 0;

    uint32_t used_times;
    uint32_t ok_times;

    switch(key) {
        case 0:
            switch (choice) {
                case 0:
                    bs_imgr_select_image(0);
                    // img_burn_info.u.data.used_count += 100;
                    break;
                case 1:
                    bs_imgr_select_image(3);
                    break;
            }

            // 更新烧录次数
            used_times = ++img_burn_info.u.data.used_count;
            ok_times = ++img_burn_info.u.data.ok_count;
            flash_level_write_entry(&img_burn_info);
            LOGI("used_count: 0x%x, ok_count: 0x%x", used_times, ok_times);

            choice++;
            if (choice == 2) choice = 0;

        break;

        case 1:
            // 读取
            ice_download_start();
        break;

        case 2:
            // 擦除

        break;

        default:
        break;
    }
#endif

    // crc 时间
    static uint8_t temp_buf[4096];
    int i;
    uint32_t crc_val;
    char index;
		index = 1;

    for (i=0; i<4096; i++) temp_buf[i] = i;
    GPIO_BOP(GPIOB) = GPIO_PIN_0;
    crc_val = crc32_continue(0, temp_buf, 4096);
    GPIO_BC(GPIOB) = GPIO_PIN_0;

    GPIO_BOP(GPIOB) = GPIO_PIN_0;
    // crc_val = uzlib_crc32(temp_buf, 4096, 0);
    GPIO_BC(GPIOB) = GPIO_PIN_0;
    char *p1 = "Hello, bassun";
    char *p2 = "hello, world";

    strncpy(p1, p2, 10);
		
		temp_buf[index] = 0x5A;

#ifdef TEST_UNIT_FILE
    bs_file_module_test();
#endif

#ifdef TEST_UNIT_IMAGE
    // bs_image_module_test();
#endif

#ifdef TEST_UNIT_FS
    bs_fs_module_test();
#endif
    return 1;
}
